package net.xdclass.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import net.xdclass.config.RabbitMQConfig;
import net.xdclass.enums.BizCodeEnum;
import net.xdclass.enums.CouponStateEnum;
import net.xdclass.enums.ProductOrderStateEnum;
import net.xdclass.enums.StockTaskStateEnum;
import net.xdclass.exception.BizException;
import net.xdclass.feign.ProductOrderFeignService;
import net.xdclass.model.ProductDO;
import net.xdclass.mapper.ProductMapper;
import net.xdclass.model.ProductMessage;
import net.xdclass.model.ProductTaskDO;
import net.xdclass.request.LockProductRequest;
import net.xdclass.request.OrderItemRequest;
import net.xdclass.service.ProductService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.xdclass.service.ProductTaskService;
import net.xdclass.until.CommonUtil;
import net.xdclass.until.JsonData;
import net.xdclass.vo.ProductVO;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 二当家小D
 * @since 2022-02-18
 */
@Slf4j
@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductDO> implements ProductService {

    @Autowired
    private ProductTaskService productTaskService;
    @Autowired
    private ProductOrderFeignService productOrderFeignService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private RabbitMQConfig rabbitMQConfig;

    @Override
    public Map<String, Object> pageProductList(int page, int size) {
        Page<ProductDO> productDOPage = new Page<>(page, size);
        Page<ProductDO> productDOPage1 = baseMapper.selectPage(productDOPage, null);
        Map<String, Object> map = CommonUtil.beanProcess(productDOPage1, ProductVO.class);
        return map;
    }

    @Override
    public ProductVO findDetailById(long product_id) {
        ProductDO productDO = baseMapper.selectById(product_id);
        ProductVO productVO = new ProductVO();
        BeanUtils.copyProperties(productDO, productVO);
        return productVO;
    }

    @Override
    public List<ProductVO> findProductsByIdBatch(List<Long> productIds) {
        List<ProductDO> productDOS = baseMapper.selectList(new QueryWrapper<ProductDO>()
                .in("id", productIds));
        List<ProductVO> collect = productDOS.stream().map(t -> {
            ProductVO productVO = new ProductVO();
            BeanUtils.copyProperties(t, productVO);
            return productVO;
        }).collect(Collectors.toList());

        return collect;
    }

    /**
     * 锁定商品库存
     * 便利商品 锁定每个商品购买数量
     * 每一次锁定的时间,都要发送延迟消息9
     *
     * @param lockProductRequest
     * @return
     */
    @Override
    public JsonData lockProductStock(LockProductRequest lockProductRequest) {
        String orderOutTradeNo = lockProductRequest.getOrderOutTradeNo();
        List<OrderItemRequest> orderItemList = lockProductRequest.getOrderItemList();
        List<Long> productIds = orderItemList.stream().map(t -> t.getProductId()).collect(Collectors.toList());

        List<ProductVO> productVOList = this.findProductsByIdBatch(productIds);
        Map<Long, ProductVO> productVOMap = productVOList.stream().collect(Collectors.toMap(ProductVO::getId, Function.identity()));

        for (OrderItemRequest i : orderItemList) {
            int rows = baseMapper.lockProductStock(i.getProductId(), i.getBuyNum());
            if (rows != 1) {
                throw new BizException(BizCodeEnum.ORDER_CONFIRM_LOCK_PRODUCT_FAIL);
            } else {
                ProductVO productVO = productVOMap.get(i.getProductId());
                ProductTaskDO productTaskDO = new ProductTaskDO();
                productTaskDO.setBuyNum(i.getBuyNum());
                productTaskDO.setLockState(StockTaskStateEnum.LOCK.name());
                productTaskDO.setProductId(i.getProductId());
                productTaskDO.setProductName(productVO.getTitle());
                productTaskDO.setOutTradeNo(orderOutTradeNo);
                productTaskService.save(productTaskDO);
                log.info("商品库存锁定 插入task成功:{}", productTaskDO);
                //发送MQ延迟消息 解锁商品库存
                ProductMessage productMessage = new ProductMessage();
                productMessage.setOutTradeNo(orderOutTradeNo);
                productMessage.setTaskId(productTaskDO.getId());
                rabbitTemplate.convertAndSend(rabbitMQConfig.getEventExchange(), rabbitMQConfig.getStockReleaseDelayRoutingKey(), productMessage);
                log.info("商品库存锁定信息延迟消息发送成功:{}", productMessage);
            }
        }


        return JsonData.buildSuccess();
    }

    @Override
    public boolean releaseProductStock(ProductMessage productMessage) {
        ProductTaskDO taskDO = productTaskService.getBaseMapper().selectOne(new QueryWrapper<ProductTaskDO>()
                .eq("id", productMessage.getTaskId()));
        if (taskDO == null) {
            log.info("工作单不存在,消息体:{}", productMessage);
        }
        //lock状态处理
        if (taskDO.getLockState().equalsIgnoreCase(StockTaskStateEnum.LOCK.name())) {
            JsonData jsonData = productOrderFeignService.queryProductOrderState(productMessage.getOutTradeNo());
            String state = jsonData.getData().toString();
            if (jsonData.getCode() == 0) {
                if (ProductOrderStateEnum.NEW.name().equalsIgnoreCase(state)) {
                    log.warn("订单状态是NEW,返回给消息队列,重新投递");
                    return false;
                }
                if (ProductOrderStateEnum.PAY.name().equalsIgnoreCase(state)) {
                    taskDO.setLockState(StockTaskStateEnum.FINISH.name());
                    productTaskService.update(taskDO, new QueryWrapper<ProductTaskDO>()
                            .eq("id", productMessage.getTaskId()));
                    log.info("订单已经支付,修改库存锁定工作单FINISH状态:{}", productMessage);
                    return true;
                }
            }
            log.warn("订单不存在,或者被取消,确认消息,修改状态为CANCEL,恢复商品库存,message:{}", productMessage);
            taskDO.setLockState(StockTaskStateEnum.CANCEL.name());
            productTaskService.update(taskDO, new QueryWrapper<ProductTaskDO>()
                    .eq("id", productMessage.getTaskId()));
            baseMapper.unlockProductStock(taskDO.getProductId(), taskDO.getBuyNum());

            return true;
        } else {
            log.warn("工作单状态不是LOCK,state={},消息体={}", taskDO.getLockState(), productMessage);
            return true;
        }
    }
}
